home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyo (Python 2.5) from __future__ import with_statement __metaclass__ = type import struct import socket import time from struct import unpack, pack from pprint import pformat, pprint from util import Storage, enum, strlist, autoassign, lookup_table, removedupes, Packable, myip, FileChunker, to_hex from path import path import util import oscar import oscar.snac as oscar import oscar.OscarUtil as oscar from oscar.rendezvous.peer import OscarPeer, ipstr from oscar.rendezvous.rendezvous import oscarcookie, map_intarg, rendezvous_tlvs import oscar.capabilities as capabilities import os import os.path as os import traceback import common from logging import getLogger log = getLogger('oscar.rz.ft') info = log.info def prettyoft(oft): return '\n'.join((lambda .0: for line in .0: '%20s: %r' % line)(list(iter(oft)))) rz = rendezvous_tlvs tlv = oscar.OscarUtil.tlv tlv_list = oscar.OscarUtil.tlv_list def send(oscar, screenname, filestorage): cookie = oscarcookie() oscar.rdv_sessions[cookie] = transfer = OutgoingOscarFileTransfer(oscar, screenname, cookie, filestorage) transfer.request() return transfer class OFTHeader(Packable): fmt = strlist('\n protocol_version 4s # Always \'OFT2\'\n length H # includes all data, including version and length\n type H # one of "types" below\n ') invars = [ (lambda self: self.protocol_version == 'OFT2'), (lambda self: self.type in self.types.values())] types = Storage(prompt = 257, ack = 514, done = 516, receiver_resume = 517, sender_resume = 262, rcv_resume_ack = 519) class OFTBody(Packable): fmt = strlist("\n cookie Q\n encryption H\n compression H\n num_files H\n files_left H\n num_parts H\n parts_left H\n total_size I\n file_size I\n\n modification_time I # since unix epoch\n checksum I # see OscarFileTransferChecksum\n recv_fork_checksum I\n fork_size I\n creation_time I\n fork_checksum I\n bytes_received I\n recv_checksum I\n id_string 32s # 32 byte right padded string: usually 'CoolFileXfer'\n\n flags B # Flags: 0x20 - Negotiation (not complete), 0x01 - Done\n list_name_offset B # always 0x1c\n list_size_offset B # always 0x11\n\n dummy_block 69s # Dummy Block - large null block for future expansion of OFT\n\n mac_file_info 16s # Mac File Info\n\n charset H # charset\n subset H # subset: 0 for ASCII, 2 for UTF-16BE, 3 for ISO-8859-1\n ") default_checksum = 0xFFFF0000L def padfilename(filename): if len(filename) < 64: filename += '\x00' * (64 - len(filename)) return filename padfilename = staticmethod(padfilename) OFTId = 'Cool FileXfer' OFTId = OFTId + '\x00' * (32 - len(OFTId)) class OscarFileTransfer(OscarPeer): def __init__(self, protocol, screenname, cookie): OscarPeer.__init__(self, protocol, screenname, cookie, capabilities.by_name['file_xfer']) common.FileTransfer.__init__(self) self.cancelled = False self.resuming = False self.on_get_buddy(self.buddy) def ch2cancel(self, data): log.info('%r cancelled by buddy', self) self.cancelled = True self.cancel_by_buddy() if data: log.info('data in a ch2 cancel: %s', to_hex(data)) def cancel_by_buddy(self): log.info('cancel_by_buddy') if self.state != self.states.CANCELLED_BY_YOU: self.state = self.states.CANCELLED_BY_BUDDY try: self.fileobj.close() except Exception: import traceback traceback.print_exc() def on_close(self): log.info('%r on_close', self) try: self.fileobj.close() except AttributeError: pass if self.state == self.states.TRANSFERRING: self.state = self.states.CONN_FAIL_XFER self.on_error() def close(self): log.info('close') try: self.socket.close() del self.socket except Exception: pass self.done = True try: self.fileobj.close() except AttributeError: pass def cancel(self, msg = '', state = None): if hasattr(self, 'socket') and self.socket: try: self.socket.cancel_timeout() except Exception: traceback.print_exc() except: None<EXCEPTION MATCH>Exception None<EXCEPTION MATCH>Exception try: self.filechunker.cancelled = True except Exception: traceback.print_exc() info('$$$ sending cancel') self.send_rdv('cancel') self.close() self.setnotifyif('cancelled', True) info('%r cancelled. %s', self, msg) if state is None: state = self.states.CANCELLED_BY_YOU self.state = state def ch2accept(self, data): if data: log.error('got data in a channel 2 accept: data = %r', data) self.cancel() else: log.info('ch2accept data = %r', data) def decline_transfer(self, reason = None): log.info('decline_transfer: reason = %r', reason) self.cancel() def send_oft(self, type, setvalues = True): oft = self.oft if not oft: return None if setvalues: oft.id_string = OFTId oft.cookie = self.cookie oft.list_name_offset = 28 oft.list_size_offset = 17 oft.flags = None if 'type' == 'done' else 32 oft.checksum = OFTBody.default_checksum info('sending oft %s for %s', type, self.filename) info(prettyoft(oft) + '\n filename: %s', self.filename) self.socket.push(oftpacket(type, oft, self.filename)) class OutgoingOscarFileTransfer(OscarFileTransfer, common.OutgoingFileTransfer): def __init__(self, o, screenname, cookie, fileinfo): OscarFileTransfer.__init__(self, o, screenname, cookie) [ setattr(self, a, fileinfo[a]) for a in 'name files size numfiles'.split() ] self.filepath = path(fileinfo.path) self.fileobj = None self.oft = self.next_file() self.accepted = False self.connected = False self.completed = 0 self.state = self.states.WAITING_FOR_BUDDY def next_file(self): if self.files: self.file = self.files.pop(0) if hasattr(self, 'rootpath'): p = self.rootpath.relpathto(self.file) self.filename = p.normpath().replace('\\', '/').replace('/', chr(1)) else: self.filename = self.file.name return self.oft_for_file(self.file) else: self.file = None return False def __repr__(self): if not getattr(self.file, 'name', None): pass return '<OutgoingOscarFileTransfer to %s (%s)>' % (self.screenname, '') def request(self, message = '<html>'): xdata = xdata_block(self.name, self.size, self.numfiles) self.establish_out_dc(message = message, extratlvs = [ (rz.extended_data, xdata), (rz.filename_encoding, 'us-ascii')]) def on_odc_connection(self): info('%r connected!', self) self.connected = True self.maybe_start() def received_oft_header(self, data): (header, data) = OFTHeader.unpack(data) log.debug('received OFT header: oft=%(protocol_version)s length=0x%(length)x type=0x%(type)x', dict(header)) bytes_left = header.length - OFTHeader._struct.size if header.type in (OFTHeader.types.ack, OFTHeader.types.rcv_resume_ack): self.open_file() elif header.type == OFTHeader.types.done: try: self.fileobj.close() except AttributeError: pass self.fileobj = None self.oft = self.next_file() if not self.oft: if self.completed: self.state = self.states.FINISHED self._ondone() else: self.cancel_by_buddy() self.close() return None elif header.type == OFTHeader.types.receiver_resume: log.info('Going to resume file %s' % self.file) self.resuming = True else: log.warning('Error! OFT type %r', header.type) self.socket.receive_next(bytes_left, self.received_oft_body) def open_file(self): try: self.fileobj = self.file.open('rb') return True except IOError: self.cancel('Could not open file %s' % self.file) return False def received_oft_body(self, data): (oft, data) = OFTBody.unpack(data) (filename, data) = read_cstring(data) info(prettyoft(oft) + '\n filename: %s', filename) self.oft = oft self.socket.receive_next(OFTHeader, self.received_oft_header) if self.fileobj: if self.resuming: self.fileobj.seek(oft.bytes_received) self._setcompleted(self.fileobj.tell()) self.filechunker = FileChunker(self.fileobj, close_when_done = True, progress_cb = self._setcompleted) log.info('Pushing FileChunker onto socket') self.socket.push_with_producer(self.filechunker) elif self.oft: if self.resuming: self.send_oft('sender_resume', False) else: self.send_oft('prompt') else: info('DONE!') self.state = self.states.FINISHED self.close() def ch2accept(self, data): info('received CH2 accept') self.accepted = True self.maybe_start() def maybe_start(self): if not (self.accepted) or not (self.connected): if not self.accepted: info('no RDV accept yet') if not self.connected: info('no connection yet') return None self.state = self.states.TRANSFERRING if not getattr(self, 'sent_first', False): info('sending first oft prompt') self.sent_first = True self.send_oft('prompt') self.socket.receive_next(OFTHeader, self.received_oft_header) def oft_for_file(self, file): return OFTBody(cookie = self.cookie, num_files = self.numfiles, files_left = 1 + len(self.files), num_parts = 1, parts_left = 1, total_size = self.size, file_size = file.size, modification_time = int(file.mtime), creation_time = int(file.ctime), checksum = OFTBody.default_checksum, recv_fork_checksum = OFTBody.default_checksum, fork_checksum = OFTBody.default_checksum, recv_checksum = OFTBody.default_checksum, id_string = OFTId, dummy_block = '\x00' * 69, mac_file_info = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', charset = 0, subset = 0) class IncomingOscarFileTransfer(OscarFileTransfer, common.IncomingFileTransfer): direction = 'incoming' def __init__(self, o, screenname, cookie): OscarFileTransfer.__init__(self, o, screenname, cookie) self.completed = 0 def handle_request(self, rendtlvs): (info, data) = unpack_extended_data(rendtlvs.extended_data) self.__dict__.update(info) self._onrequest() def accept(self, file_obj): if self.cancelled: e = OscarFileTransferError('The sender has already cancelled this file request.') self.protocol.hub.on_error(e) elif isinstance(file_obj, file) or self.numfiles == 1: self.filepath = path(file_obj.name) self.rootpath = self.filepath.parent file_obj.close() else: self.rootpath = os.path.join(file_obj, self.name) if not os.path.exists(self.rootpath): os.makedirs(self.rootpath) self.filepath = path(self.rootpath) info('self.rootpath = %r', self.rootpath) None(info, 'accepting incoming file transfer, saving %s to %s' if self.numfiles == 1 else 'files', self.rootpath) self.state = self.states.CONNECTING self.establish_dc() def decline(self): self.state = self.states.CANCELLED_BY_YOU self.send_rdv('cancel') common.IncomingFileTransfer.decline(self) def on_odc_connection(self): self.state = self.states.TRANSFERRING self.socket.receive_next(OFTHeader, self.received_oft_header) def received_oft_header(self, data): (header, data) = OFTHeader.unpack(data) log.debug('received OFT header: %r', dict(header)) if header.type == OFTHeader.types.prompt: bytes_left = header.length - OFTHeader._struct.size log.debug('receiving %d more OFT body bytes', bytes_left) self.socket.receive_next(bytes_left, self.received_oft_body) else: self.fail('Error! OFT type ' + str(header.type)) def received_oft_body(self, data): (oft, data) = OFTBody.unpack(data) self.oft = oft info('incoming oft body...\n' + prettyoft(oft)) nullindex = data.find('\x00') if nullindex == -1: raise AssertionError("couldn't find a null byte in the padded filename") self.filename = filename = data[:nullindex] self.fileobj = openpath(self.rootpath, self.filepath.name) info('incoming file: %s (%d bytes), %d left', filename, oft.file_size, oft.files_left) self.send_oft('ack') self.socket.push_collector(self.collect_file_bytes) if oft.file_size > 0: self.socket.receive_next(oft.file_size, self.received_file) else: self.received_file() def collect_file_bytes(self, data): try: self.fileobj.write(data) except IOError: import traceback traceback.print_exc() return None else: self._setcompleted(self.fileobj.tell()) finally: self.data = '' def received_file(self, *data): self.socket.pop_collector() info('received file %s', self.fileobj.name) self.fileobj.close() self.send_oft('done') if self.oft.files_left == 1: info('done!') self.socket.close() self._ondone() else: self.socket.receive_next(OFTHeader, self.received_oft_header) def fail(self, msg): log.error(msg) self.close() def __repr__(self): return '<IncomingOFT from %s>' % self.screenname def oftpacket(type, body, filename): filename = str(filename) padded = OFTBody.padfilename(filename) return ''.join([ OFTHeader('OFT2', length = 192 + len(padded), type = map_intarg(type, OFTHeader.types)).pack(), body.pack(), padded]) def oft_filename(fn): fn += chr(0) if len(fn) < 64: fn += (64 - len(fn)) * chr(0) return fn def read_cstring(data): i = data.find(chr(0)) if i == -1: raise ValueError('not a null terminated string') return (data[:i], data[i + 1:]) def unpack_extended_data(data): (multiple, filecount, totalbytes) = struct.unpack('!HHI', data[:8]) data = data[8:] (filename, data) = read_cstring(data) return (util.Storage(numfiles = filecount, multiple = multiple == 2, size = totalbytes, name = filename), data) def xdata_block(filename, filesize, filecount = 1): return None(struct.pack, '!HHI' if filecount == 1 else 2, filecount, filesize) + filename.encode('utf-8') + '\x00' def openpath(rootpath, filename): PATHSEP = chr(1) needdirs = filename.find(PATHSEP) != -1 path = filename.split(PATHSEP) filename = path.pop(-1) path = [ rootpath] + path if needdirs: pathstr = os.path.join(*path) if not os.path.exists(pathstr): info('calling makedirs(%s)', pathstr) os.makedirs(pathstr) filepath = path + [ filename] return open(os.path.join(*filepath), 'wb') class OscarFileTransferError(Exception): pass class OFTChecksum(object): starting_value = 0xFFFF0000L def __init__(self, data = None): self.checksum = self.starting_value if data is not None: self.update(data) def update(self, data, offset = 0): check = self.checksum >> 16 & 0xFFFFL for i in xrange(len(data)): oldcheck = check byteval = ord(data[offset + i]) & 255 None -= check if i & 1 != 0 else byteval << 8 if check > oldcheck: check -= 1 continue check = (check & 65535) + (check >> 16) check = (check & 65535) + (check >> 16) checksum = check << 16 & 0xFFFFFFFFL if __name__ == '__main__': p = 'c:\\users\\kevin\\desktop\\apple_evolution.jpg' bytes = open(p, 'rb').read() print OFTChecksum(bytes).checksum